package core;

import java.io.Serializable;
import java.util.Arrays;

public class Optimization implements Serializable{
	//input variables
	protected DmuList dmuList;
	//runtime variables
	protected boolean isCalculated = false;
    private long optimizationTime;
    private double efficiency =-1d;
	//output variables
	private double[] optimizationWeights;
	private double[] relOptimizationWeights;
	private double optimizationObjective;
    private int objectiveDmu;


    public int getObjectiveDmu() {
        return objectiveDmu;
    }

    public void setObjectiveDmu(int objectiveDmu) {
        this.objectiveDmu = objectiveDmu;
    }

	public DmuList getDmuList() {
		return dmuList;
	}
	public void setDmuList(DmuList dmuList) throws CalculationException {
		if(!isCalculated){
			this.dmuList = dmuList;
		}
		else{
			throw new CalculationException(CalculationException.alreadyCalculatedMessage);
		}
	}
	public Optimization(DmuList dmuList, int objectiveDmu) throws CalculationException {
		super();
		this.setDmuList(dmuList);
        this.setObjectiveDmu(objectiveDmu);
	}
        public void setOptimizationTime(long milliseconds){
        this.optimizationTime = milliseconds;
    }
    public long getOptimizationTime() throws CalculationException{
        if(this.isCalculated){
            return this.optimizationTime;
        }else{
            throw new CalculationException(CalculationException.notYetCalculatedMessage);
        }
    }
	public void setOptimizationWeights(double[] optimizationWeights) {
		this.optimizationWeights = optimizationWeights;
	}
	public double[] getOptimizationWeights() throws CalculationException {
		if(isCalculated){
			return optimizationWeights;
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
	public double getOptimizationWeight(int index) throws CalculationException {
		if(isCalculated){
			return optimizationWeights[index];
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
    public double[] getOptimizationOutputWeights() throws CalculationException{
        if(isCalculated){
			double[] outputWeights = new double[this.dmuList.outputSize];
            for(int i=0;i<outputWeights.length;i++){
                outputWeights[i] = this.optimizationWeights[i];
            }
            return outputWeights;
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
    }
	public double[] getRelOptimizationWeights() throws CalculationException {
		if(isCalculated){
			if(relOptimizationWeights == null){
				setRelOptimizationWeights();
			}
			return relOptimizationWeights;
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
	public double getRelOptimizationWeight(int index) throws CalculationException {
		if(isCalculated){
			if(relOptimizationWeights == null){
				setRelOptimizationWeights();
			}
			return relOptimizationWeights[index];
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
	private void setRelOptimizationWeights(){
		this.relOptimizationWeights = this.optimizationWeights.clone();
		for(int i = 0; i<optimizationWeights.length;i++){
			if(!(i >= optimizationWeights.length - this.dmuList.inputSize)) //only for outputs
			relOptimizationWeights[i] =optimizationWeights[i]/optimizationWeights[0];
			
		}
	}
	public void setOptimizationObjective(double optimizationObjective) {
		this.optimizationObjective = optimizationObjective;
	}
	public double getOptimizationObjective() throws CalculationException {
		if(isCalculated){
		return optimizationObjective;
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
    	public double getEfficiency() throws CalculationException {
		if(this.isCalculated){
			if(this.efficiency > -1){
				return efficiency;
			}
			else{
				this.calculateEfficiency();
				return efficiency;
			}
		}
		else{
			throw new CalculationException(CalculationException.notYetCalculatedMessage);
		}
	}
            public void setEfficiency(double efficiency) {
		this.efficiency = efficiency;
	}
    private void calculateEfficiency() throws CalculationException{
		double dist = 0.0;
		double tmp = 0.0;
        //Util.print("__________________________________");
        //Util.print(this.alpha);
		 for (int z = 0; z < dmuList.outputSize; z++) {
			 tmp = getOptimizationWeight(z) * dmuList.get(getObjectiveDmu()).criteria.get(dmuList.inputSize + z).amount;
			 dist += tmp;
			 //Util.print(getOptimizationWeight(z) + " * " + dmuList.get(getObjectiveDmu()).criteria.get(dmuList.inputSize + z).amount);
		 }
		 this.setEfficiency(dist);
	}
	public void setCalculated() throws CalculationException{
			this.isCalculated = true;
	}
	public String toString(){
		if(isCalculated){
			this.setRelOptimizationWeights();
			return this.optimizationObjective + ";" + Arrays.toString(this.relOptimizationWeights);
		}
		else{
			return "DmuList.Cnt: " + dmuList.size() + " - isCalculated: false";
		}
	}
}
